package cn.bootx.table.modify.postgresql.service;

import cn.bootx.table.modify.postgresql.annotation.DbPgSqlIndex;
import cn.bootx.table.modify.postgresql.annotation.DbPgSqlIndexes;
import cn.bootx.table.modify.postgresql.entity.PgSqlEntityIndex;
import cn.bootx.table.modify.postgresql.entity.PgSqlModifyMap;
import cn.bootx.table.modify.postgresql.util.PgSqlInfoUtil;
import cn.bootx.table.modify.utils.ClassUtils;
import cn.bootx.table.modify.utils.ColumnUtils;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.StrUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 索引处理
 * @author xxm
 * @since 2023/9/14
 */
@Slf4j
@Component
@RequiredArgsConstructor
public class PgSqlIndexInfoService {

    /**
     * 获取创建表锁需要的索引 不包括主键索引
     * @param clas 实体类
     * @param baseTableMap 用于存储各种操作PgSQL表结构的容器
     */
    public void getCreateIndex(Class<?> clas, PgSqlModifyMap baseTableMap){
        // 获取entity的tableName
        String tableName = ColumnUtils.getTableName(clas);
        // 找出实体类所有的索引
        List<PgSqlEntityIndex> entityIndexes = getEntityIndexes(clas);
        if (CollUtil.isNotEmpty(entityIndexes)) {
            baseTableMap.getAddIndexes().put(tableName, entityIndexes);
        }
    }


    /**
     * 获取实体类配置的索引
     * 首先获取实体类上创建的索引, 如果不存在, 获取字段上配置的索引
     */
    private List<PgSqlEntityIndex> getEntityIndexes(Class<?> clas){

        // 多个索引注释处理
        List<DbPgSqlIndex> indexList = Optional.ofNullable(clas.getAnnotation(DbPgSqlIndexes.class))
                .map(DbPgSqlIndexes::value)
                .map(ListUtil::of)
                .orElse(new ArrayList<>(0));
        if (CollUtil.isEmpty(indexList)) {
            // 单个注解处理
            DbPgSqlIndex dbPgSqlIndex = clas.getAnnotation(DbPgSqlIndex.class);
            if (Objects.nonNull(dbPgSqlIndex)){
                indexList = ListUtil.of(dbPgSqlIndex);
            }
        }
        // 返回处理完的索引配置
        if (CollUtil.isNotEmpty(indexList)) {
            return indexList.stream()
                    .map(index -> {
                        List<String> columns = null;
                        // 先取数据库字段名配置
                        if (Objects.nonNull(index.columns())){
                            columns = Arrays.asList(index.columns());
                        }
                        // 不存在取实体类字段配置
                        if (CollUtil.isEmpty(columns)){
                            columns = getIndexColumnName(index.fields(),clas);
                        }
                        // 如果还为空. 抛出错误
                        if (CollUtil.isEmpty(columns)){
                            throw new RuntimeException("索引字段配置为空");
                        }
                        return new PgSqlEntityIndex()
                                .setType(index.type())
                                .setName(PgSqlInfoUtil.getIndexName(index,columns))
                                .setColumns(columns)
                                .setComment(index.comment());
                    })
                    .collect(Collectors.toList());
        } else {
            return getSimpleIndexes(clas);
        }

    }

    /**
     * 获取要进行变动的的索引信息 不包括主键索引
     * @param clas 实体类
     * @param baseTableMap 用于存储各种操作PgSQL表结构的容器
     */
    public void getModifyIndex(Class<?> clas, PgSqlModifyMap baseTableMap){

    }

    /**
     * 获取实体类字段对应的数据库表字段名称
     */
    private List<String> getIndexColumnName(String[] fields,Class<?> clas){
        return Arrays.stream(fields)
                .map(fieldName->{
                    // 转换成mtm的字段名
                    Field field = ClassUtils.getField(clas, fieldName);
                    return ColumnUtils.getColumnName(field,clas);
                }).collect(Collectors.toList());
    }

    /**
     * 获取字段上配置的简单索引方式
     */
    private List<PgSqlEntityIndex> getSimpleIndexes(Class<?> clas){
        // 实体类上未声明索引, 开始遍历字段找到索引配置, 进行简单索引方式处理
        Field[] fields = clas.getDeclaredFields();
        fields = ClassUtils.recursionParents(clas, fields);
        return Arrays.stream(fields).map(field->{
                    DbPgSqlIndex index = field.getAnnotation(DbPgSqlIndex.class);
                    if (Objects.isNull(index)){
                        return null;
                    }
                    PgSqlEntityIndex mySqlEntityIndex = new PgSqlEntityIndex()
                            .setType(index.type());
                    // 字段
                    String columnName = ColumnUtils.getColumnName(field, clas);
                    mySqlEntityIndex.setColumns(Collections.singletonList(columnName));
                    // 名称
                    if (StrUtil.isNotBlank(index.name())){
                        mySqlEntityIndex.setName(index.name());
                    } else {
                        mySqlEntityIndex.setName(columnName);
                    }
                    // 注释
                    if (StrUtil.isNotBlank(index.comment())){
                        mySqlEntityIndex.setComment(index.comment());
                    }
                    return mySqlEntityIndex;
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());
    }
}
